#include "thread.h"
#include "log.h"
#include "util.h"

namespace sylar {

// 线程局部变量
// 用于获取当前正在运行的 Thread 对象
static thread_local Thread* t_thread = nullptr;
// 用于获取当前线程名
static thread_local std::string t_thread_name = "UNKNOW";

// 日志
static sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("system");

Semaphore::Semaphore(uint32_t count) {
  // 初始化信号量
  if(sem_init(&m_semaphore, 0, count)) {
    throw std::logic_error("sem_init error");
  }
}

Semaphore::~Semaphore() {
  // 销毁信号量
  sem_destroy(&m_semaphore);
}

void Semaphore::wait() {
  // 等待信号量
  if(sem_wait(&m_semaphore)) {
    throw std::logic_error("sem_wait error");
  }
}

void Semaphore::notify() {
  // 发出通知
  if(sem_post(&m_semaphore)) {
    throw std::logic_error("sem_post error");
  }
}

Thread* Thread::GetThis() {
  return t_thread;
}

const std::string& Thread::GetName() {
  return t_thread_name;
}

void Thread::SetName(const std::string& name) {
  // 当前 Thread 对象存在时设置名字
  if(t_thread) {
    t_thread->m_name = name;
  }
  t_thread_name = name;
}

Thread::Thread(std::function<void()> cb, const std::string& name)
  :m_cb(cb)
  ,m_name(name) {
  if(name.empty()) {
    m_name = "UNKNOW";
  }
  int rt = pthread_create(&m_thread, nullptr, &Thread::run, this);
  // 如果创建线程失败，则输出日志
  if(rt) {
    SYLAR_LOG_ERROR(g_logger) << "pthread_create thread fail, rt=" << rt
        << " name=" << name;
    throw std::logic_error("pthread_create error");
  }
  // 等待 run 开始执行 cb 才能完成构造，防止过早析构
  m_semaphore.wait();
}

Thread::~Thread() {
  // 析构时分离当前线程，以确保他自己能顺利执行
  if(m_thread) {
    pthread_detach(m_thread);
  }
}

void Thread::join() {
  if(m_thread) {
    int rt = pthread_join(m_thread, nullptr);
    // jion 失败则输出日志
    if(rt) {
      SYLAR_LOG_ERROR(g_logger) << "pthread_join thread fail, rt=" << rt
          << " name=" << m_name;
      throw std::logic_error("pthread_join error");
    }
    // join 成功之后，将当前线程置空
    m_thread = 0;
  }
}

// pthread_create 创建时使用的接口
// arg 为 Thread 对象
void* Thread::run(void* arg) {
  Thread* thread = (Thread*)arg;
  t_thread = thread;
  t_thread_name = thread->m_name;
  thread->m_id = sylar::GetThreadId();
  // 设置系统中的线程名称，不能超出 16 个字符
  pthread_setname_np(pthread_self(), thread->m_name.substr(0, 15).c_str());

  std::function<void()> cb;
  // thread 对象有可能提前析构，因此不能直接使用 thread->m_cb
  cb.swap(thread->m_cb);

  // 通知构造函数 cb 已 swap 结束
  thread->m_semaphore.notify();

  // 实际运行此回调函数
  cb();
  return 0;
}

}
